/** @jsxImportSource @emotion/react */
import React, {
    Children,
    cloneElement,
    forwardRef,
    isValidElement, MouseEventHandler,
    useEffect,
    useMemo,
    useRef,
    useState
} from "react";
import {
    useFloating,
    offset,
    flip,
    shift,
    useListNavigation,
    useHover,
    useTypeahead,
    useInteractions,
    useRole,
    useClick,
    useDismiss,
    autoUpdate,
    safePolygon,
    FloatingPortal,
    useFloatingTree,
    useFloatingNodeId,
    useFloatingParentNodeId,
    FloatingNode,
    FloatingTree,
    FloatingFocusManager
} from "@floating-ui/react-dom-interactions";
import cx from "classnames";
import { mergeRefs } from "react-merge-refs";
// import {useTheme} from "./Theme/Providers";
import {Menu2Item} from "./Menu";

import {
    useTheme,
} from "customize-easy-ui-component";



/*直接改造 源自官方例子的： https://codesandbox.io/s/admiring-lamport-5wt3yg?file=/src/DropdownMenu.tsx
样式直接文件注入的形式：
原来例子 import "./styles.css";
* */


/** 叶子节点的菜单项目； 必须放在DdMenu下面的；
注意这样的 <DdMenu label="菜单"  icon={<IconMoreVertical />}>
            <React.Fragment>
                <DdMenuItem label="Undo" />
【特别注意】多套一层<></>就无法正常工作的。
# 若有children儿子的就显示为儿子。否则就按照label显示的。 两个情况的样式控制不同。
实际上：forwardRef<T, P = {}> 在P模型中定义onClick是关键触发！
* */
export const DdMenuItem = forwardRef< HTMLButtonElement,
        {
            label: string;
            disabled?: boolean;
            onClick?: MouseEventHandler | undefined;
            children?: React.ReactNode;
            onPress?: MouseEventHandler | undefined;     //可兼容性
            contentAfter?: React.ReactNode;
            contentBefore?: React.ReactNode;      //前置的图标按钮<Menu2Item透传参数;
        }
    >((
            {  label,
               disabled,
               //onClick,
               children,
               ...props
            }, ref
) => {

    //支持嵌套组件的属性参数透明传递：  {...props}  方式就可以传递 css= style= 儿子组件 等。类似{... other}做法的...bind()。
      //const { getItemProps } = useInteractions();
    //【特别注意】元素的tag标签对样式影响大component={"div"} #={"button"} 用div更好；
    //底下<Menu2Item ref= 实际可以加上{ ...getItemProps({ onClick,  style: { },  }) }的。
    return (
        <Menu2Item
           ref={ref}
           role="menuitem"
           disabled={disabled}
           style={{       //MenuItem#
               display: 'flex',
            }}
           css={{
               //maxWidth: '10rem',         不灵活的
               background:  'ghostwhite',
               ":focus,:not([disabled]):active": {          //点亮的
                    //color: 'red',
                    background:  'mistyrose'
               },
           }}

          {...props}
        >
         {children? children : label }
        </Menu2Item>
    );
});

//无需要公开的external ?
interface Props {
    //可支持搜索菜单项目的 文本。
    label?: string;
    //实际 没必要的参数
    nested?: boolean;
    children?: React.ReactNode;
    //后面安放的图标
   // contentAfter?: React.ReactNode;
    //前面安放的图标
   //  contentBefore?: React.ReactNode;
    //任意的组件， 简易按钮 图标
    icon?: React.ReactNode;
    //菜单按钮的样式 ：还是能独立配置为佳。
    divStyle?: React.CSSProperties;
    /**可以将这里没定义的参数 tight={true} 透明传递下去。
     * */
    [key: string]: any;     //任意参数传递模式！
}

/**不是叶子的节点菜单项。根部或者嵌套的树杈按钮。
 * 注意icon有没有会影响到树杈或者根部按钮菜单项的高度！icon决定了到底是string纯粹文本的，还是嵌套div组件图标按钮的。
 * 若有icon={}的就显示为图标组件。否则就按照label显示的。 两个情况的样式控制不同。
 * */
export const MenuComponent = forwardRef<
    any,
    Props & React.HTMLProps<HTMLButtonElement>
    >(({
                  icon,
                  children,
                  label,
                  divStyle,
                  ...props }, ref
) => {
      const theme = useTheme();
    const [open, setOpen] = useState(false);
    const [activeIndex, setActiveIndex] = useState<number | null>(null);
    const [allowHover, setAllowHover] = useState(false);

    const listItemsRef = useRef<Array<HTMLButtonElement | null>>([]);
    const listContentRef = useRef(
        Children.map(children, (child) =>
            isValidElement(child) ? child.props.label : null
        ) as Array<string | null>
    );

    const tree = useFloatingTree();
    const nodeId = useFloatingNodeId();
    const parentId = useFloatingParentNodeId();
    //不是嵌套的树杈节点，就是树根root的：
    const nested = parentId != null;

    const { x, y, reference, floating, strategy, refs, context } = useFloating<
        HTMLButtonElement
        >({
        open,
        onOpenChange: setOpen,
        middleware: [
            offset({ mainAxis: 4, alignmentAxis: nested ? -5 : 0 }),
            flip(),
            shift()
        ],
        placement: nested ? "right-start" : "bottom-start",
        nodeId,
        whileElementsMounted: autoUpdate
    });

    const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(
        [
            useHover(context, {
                handleClose: safePolygon({ restMs: 25 }),
                enabled: nested && allowHover,
                delay: { open: 75 }
            }),
            useClick(context, {
                toggle: !nested,
                event: "mousedown",
                ignoreMouse: nested
            }),
            useRole(context, { role: "menu" }),
            useDismiss(context),
            useListNavigation(context, {
                listRef: listItemsRef,
                activeIndex,
                nested,
                onNavigate: setActiveIndex
            }),
            useTypeahead(context, {
                listRef: listContentRef,
                onMatch: open ? setActiveIndex : undefined,
                activeIndex
            })
        ]
    );

    // Event emitter allows you to communicate across tree components.
    // This effect closes all menus when an item gets clicked anywhere
    // in the tree.
    useEffect(() => {
        function onTreeClick() {
            setOpen(false);

            if (parentId === null) {
                refs.reference.current?.focus();
            }
        }

        tree?.events.on("click", onTreeClick);
        return () => {
            tree?.events.off("click", onTreeClick);
        };
    }, [parentId, tree, refs]);

    // Determine if "hover" logic can run based on the modality of input. This
    // prevents unwanted focus synchronization as menus open and close with
    // keyboard navigation and the cursor is resting on the menu.
    useEffect(() => {
        function onPointerMove() {
            setAllowHover(true);
        }

        function onKeyDown() {
            setAllowHover(false);
        }

        window.addEventListener("pointermove", onPointerMove, {
            once: true,
            capture: true
        });
        window.addEventListener("keydown", onKeyDown, true);
        return () => {
            window.removeEventListener("pointermove", onPointerMove, {
                capture: true
            });
            window.removeEventListener("keydown", onKeyDown, true);
        };
    }, [allowHover]);

    const mergedReferenceRef = useMemo(() => mergeRefs([ref, reference]), [
        reference,
        ref
    ]);

    //底下的<Menu2Item {...props } 注意优先级替换配置，才能把外部样式css={ {的都注入进来。
    //从上级<DdMenu接收 tight={true} 参数 到...props,  然后传递给了<Menu2Item ；
    return (
        <FloatingNode id={nodeId}>

            <Menu2Item
                {...getReferenceProps({
                    ...props,
                    ref: mergedReferenceRef,
                    onClick(event) {
                        event.stopPropagation();
                        (event.currentTarget as HTMLButtonElement).focus();
                        console.log("弹出菜单前onClick!点了");
                    },
                    ...(nested
                        ? {
                            className: cx("MenuItem", { open }),
                            role: "menuitem",
                            onKeyDown(event) {
                                // Prevent more than one menu from being open.
                                if (event.key === "ArrowUp" || event.key === "ArrowDown") {
                                    setOpen(false);
                                }
                            }
                        }
                        : {
                            className: cx("RootMenu", { open }),
                        }),
                    style: {
                       //backgroundColor: 'white', 【特别注意】去掉才能从外部注入，估计这里设置的优先级别高的！覆盖掉外部配置
                    },
                })}
                css={{
                    justifyContent: 'space-between',
                    ":hover": {
                       //color: 'blue',
                    },
                    ...divStyle,
                }}
            >
               {icon && icon}
               {!icon && label} {!icon && nested && <span style={{ marginLeft: 11 }}>➔</span>}
            </Menu2Item>

            <FloatingPortal>
                {open && (
                    <FloatingFocusManager
                        context={context}
                        modal={!nested}
                        returnFocus={!nested}
                        // Touch-based screen readers will be able to navigate back to the
                        // reference and click it to dismiss the menu without clicking an item.
                        // This acts as a touch-based `Esc` key. A visually-hidden dismiss button
                        // is an alternative.
                        order={["reference", "content"]}
                    >
                        <div className="MGroup"
                            style={{
                            }}
                            {...getFloatingProps({
                                className: "Menu",
                                ref: floating,
                                style: {
                                    position: strategy,
                                    top: y ?? 0,
                                    left: x ?? 0,
                                    zIndex: theme.zIndices.menus,     //若遭遇iframe的窗口大小，还是无法突破的，受限iframe。
                                    background: 'white',
                                    boxShadow: theme.shadows["md"],
                                    borderRadius: theme.radii.md
                                },
                                onKeyDown(event) {
                                    if (event.key === "Tab") {
                                        setOpen(false);
                                    }
                                },
                                // onClick(event) {
                                //     console.log("MGroup乱加了onClick点了");
                                // },
                            })}
                        >
                            {Children.map(
                                children,
                                (child, index) =>
                                    isValidElement(child) &&
                                    cloneElement(
                                        child,
                                        getItemProps({
                                            tabIndex: -1,
                                            role: "menuitem",
                                            className: "MenuItem",
                                            ref(node: HTMLButtonElement) {
                                                listItemsRef.current[index] = node;
                                            },
                                            onClick(e) {
                                                e.stopPropagation();
                                                console.log("Press菜单项前");
                                                if(!child.props.disabled && child.props.onClick)
                                                    child.props.onClick();
                                                tree?.events.emit("click");
                                            },
                                            // By default `focusItemOnHover` uses `mousemove` to sync focus,
                                            // but when a menu closes we want this to sync it on `enter`
                                            // even if the cursor didn't move. NB: Safari does not sync in
                                            // this case.
                                            onPointerEnter() {
                                                if (allowHover) {
                                                    setActiveIndex(index);
                                                }
                                            },
                                            style: {
                                                //lineHeight: '4.0',纯文本不会被这个约束！只有父辈树杈按钮有icon={}的才会被影响。
                                            },
                                        })
                                    )
                            )}
                        </div>
                    </FloatingFocusManager>
                )}
            </FloatingPortal>
        </FloatingNode>
    );
});

/**根部或者嵌套分支的菜单项： 可自由互动布局的 菜单；
<DdMenu>和 <DdMenuItem>不能够拆解分开！｛｝传递组件参数时要注意。
【注意】icon={}属性可以直接头传给儿子组件<MenuComponent >的，
 <DdMenu label="菜单" divStyle={{ lineHeight: '1.0'} }>
纯文本树杈根部按钮可以用 divStyle={{ lineHeight: '1.0'} } 来修正样式控制的，若有参数icon={}就不同了。
例子<DdMenu label="搜索文字"  icon={
      <Menu2Item variant="ghost">
          <IconMoreVertical />
      </Menu2Item>
  }>  <DdMenuItem...个的  </DdMenu>
* */
export const DdMenu: React.FC<Props> = forwardRef(
    (props, ref) => {

    const parentId = useFloatingParentNodeId();

    //支持嵌套组件的属性参数透明传递：  {...props}  方式就可以传递 icon={} css= style= 儿子组件 等。
    if (parentId == null) {
        return (
            <FloatingTree>
                <MenuComponent {...props} ref={ref}
                />
            </FloatingTree>
        );
    }

    return <MenuComponent {...props} ref={ref}
    />;
} );



/* 样式例子
   css={{
       "&.active": {
           fontSize: '32px',
       },
       ":hover": {
           background: 'green',
           fontSize: '32px',
       }
   }}
* */